chore: message intro with button#155
Conversation
WalkthroughUpdates a Telegram Atrium component’s layout/text, enhances start parameter parsing in the start page to support a new flow/ route, and revises the daily-report task to create a flow item, send a teaser to Telegram, and attach an inline button linking to the Atrium app via startapp data. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant CRON as Scheduler
participant Task as daily-report.ts
participant Repo as repository.flow
participant TG as Telegram API
participant User as Telegram User
CRON->>Task: Run daily report
Task->>Repo: createItem(finalMessage as description)
Repo-->>Task: flowItem(id)
Note right of Task: Build startapp data: "flow{separator}{id}"
Task->>TG: sendMessage(prepared teaser, inline button → t.me/.../app?startapp=flow{sep}{id})
TG-->>User: Teaser with “Open Atrium” button
sequenceDiagram
autonumber
participant User as Telegram User
participant TG as Telegram App
participant Atrium as startapp.vue Router
participant Pages as /epic/* or /flow/*
User->>TG: Tap “Open Atrium” (startapp=key{sep}value)
TG->>Atrium: Launch with tgWebAppStartParam
Atrium->>Atrium: Parse key/value by separator
alt key=="epic" and value
Atrium->>Pages: Navigate to /epic/{value}
else key=="flow" and value
Atrium->>Pages: Navigate to /flow/{value}
else missing/invalid
Atrium->>Pages: Navigate to /
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (6)
apps/atrium-telegram/app/components/StaffBlock.vue (2)
7-9: Make the tile accessible and keyboard-activatable; also verifyw-18utility.
- The clickable div lacks button semantics and keyboard handlers. Add role/tabindex and Enter/Space handlers.
- Please confirm
w-18exists in your utility scale (Tailwind default doesn’t include 18; if using UnoCSS/Windi or a custom scale, it’s fine).<div v-for="user in allUsers" :key="user.id" - class="w-18 flex flex-col gap-1 justify-start items-center scroll-ml-6 snap-start motion-preset-slide-right" - @click="handleClick(user.id)" + class="w-18 flex flex-col gap-1 justify-start items-center scroll-ml-6 snap-start motion-preset-slide-right" + role="button" + tabindex="0" + :aria-label="`Открыть Telegram ${user.name} ${user.surname ?? ''}`" + @click="handleClick(user.id)" + @keydown.enter.prevent="handleClick(user.id)" + @keydown.space.prevent="handleClick(user.id)" >
33-35: Guard against invalid/missing dates in the offline label.If
onlineAtis falsy/invalid,new Date('')can yield “Invalid Date” in some helpers. Add a safe fallback.- <p class="text-xs/3 text-muted text-center line-clamp-2"> - {{ user.isOnline ? 'Онлайн' : useTimeAgoIntl(new Date(user.onlineAt ?? '')) }} - </p> + <p class="text-xs/3 text-muted text-center line-clamp-2"> + {{ user.isOnline ? 'Онлайн' : (user.onlineAt ? useTimeAgoIntl(new Date(user.onlineAt)) : '—') }} + </p>apps/atrium-telegram/app/pages/startapp.vue (3)
11-20: Return after redirects to avoid multiple navigations.Without
return, execution continues and may trigger additional navigation.if (!key || !value) { - await navigateTo('/') + return await navigateTo('/') }
21-28: Handle unknown keys with a default route; ensure single-exit navigation.Add an explicit fallback for unexpected keys and return on every branch.
- if (key === 'epic') { - await navigateTo(`/epic/${value}`) - } - - if (key === 'flow') { - await navigateTo(`/flow/${value}`) - } + if (key === 'epic') { + return await navigateTo(`/epic/${value}`) + } else if (key === 'flow') { + return await navigateTo(`/flow/${value}`) + } else { + return await navigateTo('/') + }
7-7: Extract shared separator constant into a single moduleDuplicate
const separator = 'zzzzz'found in:
- apps/web-app/server/tasks/ai/daily-report.ts
- apps/web-app/server/api/beacon/epic/comment.post.ts
- apps/atrium-telegram/app/pages/startapp.vue
- apps/storefront-telegram/app/pages/startapp.vue
Move the constant to a shared package (e.g., packages/shared or packages/constants), export a named constant, and import it in these files to prevent subtle mismatches.
apps/web-app/server/tasks/ai/daily-report.ts (1)
71-81: Use the encoded param and avoid hardcoding the bot username.
- Switch to
startAppParam(encoded).- Consider moving
sushi_atrium_botto runtime config (e.g.,telegram.botUsername) to prevent drift.- await useAtriumBot().api.sendMessage(telegram.teamGroupId, preparedMessage, { + await useAtriumBot().api.sendMessage(telegram.teamGroupId, preparedMessage, { link_preview_options: { is_disabled: true, }, reply_markup: { inline_keyboard: [[{ text: '👉 Открыть Атриум', - url: `https://t.me/sushi_atrium_bot/app?startapp=${startAppData}`, + url: `https://t.me/sushi_atrium_bot/app?startapp=${startAppParam}`, }]], }, })Optional config-driven URL (outside this diff):
// useRuntimeConfig().telegram.botUsername const appUrl = `https://t.me/${telegram.botUsername}/app?startapp=${startAppParam}`
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/atrium-telegram/app/components/StaffBlock.vue(2 hunks)apps/atrium-telegram/app/pages/startapp.vue(2 hunks)apps/web-app/server/tasks/ai/daily-report.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/web-app/server/tasks/ai/daily-report.ts (2)
packages/database/src/repository/index.ts (1)
repository(63-63)apps/web-app/server/services/telegram/atrium-bot.ts (1)
useAtriumBot(95-101)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (4)
apps/atrium-telegram/app/components/StaffBlock.vue (2)
3-3: LGTM on tighter grid spacing.The reduced inner gap and wrapping look fine and should fit more tiles per row.
29-31: Name line addition looks good.Bold + clamp improves scannability without overflow.
apps/atrium-telegram/app/pages/startapp.vue (1)
2-2: Loader tweak is fine.
size-8 text-primary animate-spinreads well for a transient splash.apps/web-app/server/tasks/ai/daily-report.ts (1)
67-70: Teaser generation looks good.40-word intro + CTA is concise and should improve CTR while keeping the full text in Atrium.
| const flowItem = await repository.flow.createItem({ | ||
| type: 'daily_task_report', | ||
| title: `Задачи ${date}`, | ||
| description: finalMessage, | ||
| }) |
There was a problem hiding this comment.
Guard against missing flowItem.id to avoid sending broken links.
If createItem fails or returns no id, the URL becomes ...startapp=flowzzzzzundefined. Bail out early.
const flowItem = await repository.flow.createItem({
type: 'daily_task_report',
title: `Задачи ${date}`,
description: finalMessage,
})
+
+ if (!flowItem?.id) {
+ logger.warn('daily-report: flow item was not created or has no id; skipping Telegram post')
+ return { result: true }
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const flowItem = await repository.flow.createItem({ | |
| type: 'daily_task_report', | |
| title: `Задачи ${date}`, | |
| description: finalMessage, | |
| }) | |
| const flowItem = await repository.flow.createItem({ | |
| type: 'daily_task_report', | |
| title: `Задачи ${date}`, | |
| description: finalMessage, | |
| }) | |
| if (!flowItem?.id) { | |
| logger.warn('daily-report: flow item was not created or has no id; skipping Telegram post') | |
| return { result: true } | |
| } |
🤖 Prompt for AI Agents
In apps/web-app/server/tasks/ai/daily-report.ts around lines 58 to 62, the code
assumes repository.flow.createItem returns an object with id and will build a
URL using flowItem.id; add a guard to check that flowItem exists and has a
truthy id before proceeding to build or send any links — if missing, log an
error/warning and return early (or throw) to avoid producing a URL containing
"undefined". Ensure any callers handle this early exit and include a clear log
message with the failed response details for debugging.
| const separator = 'zzzzz' | ||
| const startAppData = `flow${separator}${flowItem?.id}` | ||
|
|
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Encode and centralize startapp payload.
- URL-encode the payload to be safe.
- Reuse a shared
TG_STARTAPP_SEPARATORconstant across server and client.
- const separator = 'zzzzz'
- const startAppData = `flow${separator}${flowItem?.id}`
+ const separator = 'zzzzz' // TODO: import from shared constants
+ const startAppData = `flow${separator}${flowItem.id}`
+ const startAppParam = encodeURIComponent(startAppData)Verification helper:
🏁 Script executed:
#!/bin/bash
# Check all usages of the separator and startapp param construction.
rg -nP "zzzzz|startapp=" -C2Length of output: 2436
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== apps/web-app/server/tasks/ai/daily-report.ts ==="
nl -ba apps/web-app/server/tasks/ai/daily-report.ts | sed -n '1,220p' || true
echo
echo "=== apps/web-app/server/api/beacon/epic/comment.post.ts ==="
nl -ba apps/web-app/server/api/beacon/epic/comment.post.ts | sed -n '1,220p' || true
echo
echo "=== apps/atrium-telegram/app/pages/startapp.vue ==="
nl -ba apps/atrium-telegram/app/pages/startapp.vue | sed -n '1,240p' || true
echo
echo "=== apps/storefront-telegram/app/pages/startapp.vue ==="
nl -ba apps/storefront-telegram/app/pages/startapp.vue | sed -n '1,240p' || trueLength of output: 389
Centralize TG_STARTAPP_SEPARATOR and URL‑encode startapp payload
Local 'zzzzz' separator found in:
- apps/web-app/server/tasks/ai/daily-report.ts
- apps/web-app/server/api/beacon/epic/comment.post.ts
- apps/atrium-telegram/app/pages/startapp.vue
- apps/storefront-telegram/app/pages/startapp.vue
Actions:
- Export a single TG_STARTAPP_SEPARATOR from a shared module and import it in all server/client files (replace each local "zzzzz").
- Encode the payload on the server: const startAppParam = encodeURIComponent(startAppData); use ?startapp=${startAppParam} in URLs.
- Decode on the client before parsing: const startAppData = decodeURIComponent(tgWebAppStartParam as string || ''); then split by TG_STARTAPP_SEPARATOR.
- Do not remove optional chaining (e.g., flowItem?.id) unless you verify the value is always present.
🤖 Prompt for AI Agents
In apps/web-app/server/tasks/ai/daily-report.ts around lines 64-66, replace the
local separator ('zzzzz') with a shared constant exported from a common module
(e.g., TG_STARTAPP_SEPARATOR) and import it here and in the other listed files;
when building the startapp payload, URL-encode it on the server (use
encodeURIComponent) and use ?startapp=<encoded> in generated URLs; on the client
decode with decodeURIComponent before parsing (then split by
TG_STARTAPP_SEPARATOR) and keep optional chaining (e.g., flowItem?.id) as-is
unless you can guarantee the value is present.



Summary by CodeRabbit
New Features
UI
Content